package sf.database.template.enjoy;

import com.jfinal.template.source.StringSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sf.database.OrmConfig;
import sf.database.jdbc.sql.SQLContext;
import sf.database.jdbc.sql.SQLParameter;
import sf.database.template.TemplateHandler;
import sf.database.template.TemplateRender;
import sf.database.template.TemplateType;
import sf.database.template.enjoy.ext.SqlPara;
import sf.database.template.sql.SqlHelp;
import sf.tools.IOUtils;
import sf.tools.StringUtils;

import java.io.IOException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * enjoy模板实现类
 */
public class EnjoyHandler implements TemplateHandler {
    private static final Logger logger = LoggerFactory.getLogger(EnjoyHandler.class);
    private static volatile boolean initialized = false;

    private static EnjoyHandler instance;

    public static EnjoyHandler getInstance() {
        if (instance == null) {
            instance = new EnjoyHandler();
        }
        return instance;
    }


    private EnjoyHandler() {

    }


    @Override
    public void loadAllSQL() {
        Set<URL> set = Collections.emptySet();
        Map<String, String> pathMap = OrmConfig.getInstance().getSqlTemplatePaths();
        if (pathMap != null && pathMap.containsKey(TemplateType.enjoy.name())) {
            String paths = pathMap.get(TemplateType.enjoy.name());
            if (StringUtils.isNotBlank(paths)) {
                set = TemplateRender.getSqlTemplates(StringUtils.split(paths, ","));
            }
        } else {
            set = TemplateRender.getDefaultSqlTemplates();
        }
        StringBuilder sb = new StringBuilder();
        for (URL r : set) {
            try {
                IOUtils.asStringLambda(r.openStream(), StandardCharsets.UTF_8, true, line -> {
                    line = replaceSingleNotes(line);
                    if (StringUtils.isNotBlank(line)) {
                        sb.append(sb.length() > 0 ? " " : "").append(line.trim());
                    }
                    return true;
                });
                String content = SqlHelp.replaceLineSql(sb.toString());
                sb.delete(0, sb.length());
                //必须有内容
                if (StringUtils.isNotBlank(content)) {
                    StringSource ss = new StringSource(content, true);
                    EnjoyHelp.getEnjoySqlKit().addSqlTemplate(ss);
                }
            } catch (IOException e) {
                logger.error("", e);
            }
        }
        EnjoyHelp.getEnjoySqlKit().parseSqlTemplate();
        initialized = true;
    }

    /**
     * 去除单行注释
     * @param line
     * @return
     */
    public static String replaceSingleNotes(String line) {
        if (line.contains("###")) {
            line = line.substring(0, line.indexOf("###"));
        }
        int a = line.indexOf("#--");
        int b = line.indexOf("--#");
        int c = line.indexOf("--");
        if (b >= 0 && b + 3 < line.length()) {
            c = line.indexOf("--", b + 3);
        }
        if (c > b && (b >= 0 || a < 0)) {
            line = line.substring(0, c);
        }
        return line;
    }

    @Override
    public String getSQL(String sqlId) {
        if (!initialized) {
            loadAllSQL();
            //是否开启debug模式
            if (!OrmConfig.getInstance().isSqlTemplateDebug()) {// 非debug模式则初始化一次
                initialized = true;
            }
        }
        return null;
    }

    @Override
    public SQLContext getParsedSql(String sqlId, String dbType, Map<String, Object> parameters) {
        getSQL(null);
        SqlPara sp = EnjoyHelp.getEnjoySqlKit().getSqlPara(sqlId, dbType, parameters);
        return getSQLContext(sp);
    }

    @Override
    public SQLContext getParsedPageSqlSource(String sqlSource, Map<String, Object> parameters) {
        getSQL(null);
        SqlPara sp = EnjoyHelp.getEnjoySqlKit().getSqlParaPageSource(sqlSource, parameters);
        return getPageSQLContext(sp);
    }

    public SQLContext getSQLContext(SqlPara sp) {
        SQLContext context = new SQLContext();
        String sql = sp.getSql();
//        sql = SqlHelp.replaceLineSql(sql);
        context.setSql(sql);
        if (sp.getPara() != null) {
            List<SQLParameter> list = new ArrayList<>();
            for (Object o : sp.getPara()) {
                SQLParameter p = new SQLParameter();
                p.setValue(o);
                list.add(p);
            }
            context.setParas(list);
        }
        return context;
    }

    @Override
    public SQLContext getParsedPageSql(String sqlId, String dbType, Map<String, Object> parameters) {
        getSQL(null);
        SqlPara sp = EnjoyHelp.getEnjoySqlKit().getSqlParaPage(sqlId, dbType, parameters);
        return getPageSQLContext(sp);
    }

    @Override
    public SQLContext getParsedSqlSource(String sqlSource, Map<String, Object> parameters) {
        SqlPara sp = EnjoyHelp.getEnjoySqlKit().getSqlParaBySource(sqlSource, parameters);
        return getSQLContext(sp);
    }


    public SQLContext getPageSQLContext(SqlPara sp) {
        SQLContext context = new SQLContext();
        String sql = sp.getListSql();//
//        sql = SqlHelp.replaceLineSql(sql);
        context.setListSql(sql);
        String countSql = sp.getCountSql();
//        countSql = SqlHelp.replaceLineSql(countSql);
        context.setCountSql(countSql);
        if (sp.getPara() != null) {
            List<SQLParameter> list = new ArrayList<>();
            for (Object o : sp.getPara()) {
                SQLParameter p = new SQLParameter();
                p.setValue(o);
                list.add(p);
            }
            context.setParas(list);
        }
        return context;
    }

    @Override
    public SQLContext getParsedPageCountSql(String sqlId, String dbType, Map<String, Object> parameters) {
        return null;
    }

    @Override
    public SQLContext getParsedPageCountSqlSource(String sqlSource, Map<String, Object> parameters) {
        return null;
    }

    @Override
    public SQLContext getParsedPageListSql(String sqlId, String dbType, Map<String, Object> parameters) {
        return null;
    }

    @Override
    public SQLContext getParsedPageListSqlSource(String sqlSource, Map<String, Object> parameters) {
        return null;
    }
}
